// Copyright 2020 morgine.com. All rights reserved.

package main

import (
	"crypto/rand"
	"flag"
	"gitee.com/tugoer/psys/container"
	"gitee.com/tugoer/psys/cros"
	"gitee.com/tugoer/psys/env"
	"gitee.com/tugoer/psys/handlers"
	"gitee.com/tugoer/psys/models"
	"gitee.com/tugoer/psys/services"
	"gitee.com/tugoer/psys/utils"
	"github.com/gin-gonic/gin"
	"github.com/morgine/log"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var username = "chaoyu001"
var password = "chaoyu001"

func main() {
	addr := flag.String("a", ":8080", "监听地址")
	migrate()
	engine := gin.New()
	if env.Env.LogHTTP {
		engine.Use(gin.Logger())
	}
	engine.Use(func(ctx *gin.Context) {
		ctx.Next()
		if ctx.Errors != nil {
			panic(ctx.Errors)
		}
	})
	gin.SetMode(gin.DebugMode)
	registerRoutes(engine)
	runTicker()

	_, err := handlers.Register(username, password)
	if err != nil && err != handlers.ErrAdminUsernameAlreadyRegistered {
		panic(err)
	}
	_, err = handlers.SignIn(username, password)
	if err != nil {
		panic(err)
	}
	log.Init.Printf("listen at http://localhost%s\n", *addr)
	err = engine.Run(*addr)
	if err != nil {
		log.Panic.Println(err)
	}
}

func runTicker() {
	var TickerStartHour = 4 // 每天 4 点开始

	var runner = utils.NewDayTicker(TickerStartHour, false)
	var logsDir = "./logs"
	err := os.MkdirAll(logsDir, os.ModePerm)
	if err != nil {
		panic(err)
	}
	var old io.WriteCloser
	runner.AddCallback(func(now *time.Time) {
		// 记录日志
		var f *os.File
		f, err = os.Create(filepath.Join(logsDir, now.Format("2006-01-02")+".log"))
		if err != nil {
			log.Panic.Println(err)
		}
		log.SetOutput(log.FlagDanger|log.FlagEmergency|log.FlagError|log.FlagInfo|log.FlagInit|log.FlagPanic|log.FlagWarning, f)
		if old != nil {
			old.Close()
		}
		old = f
		// 删除缓存
		err := container.RemoveSubjects()
		if err != nil {
			log.Emergency.Println(err)
		}
	})
}

func migrate() {
	err := services.Gorm.AutoMigrate(
		&models.JsonData{},
		&models.Admin{},
		&models.Image{},
		&models.Label{},
	).Error

	if err != nil {
		panic(err)
	}
	var sliderImageLabel = &models.Label{
		Key:         "mkhuYtwie729dolvpwuqh16738cjrfusi",
		Name:        "首页滚动栏",
		Width:       640,
		Height:      158,
		AllowedEdit: models.True,
	}

	var advertisementImageLabel = &models.Label{
		Key:         "mvcnbjkfldoieu59t874jfdyqixbzfgdkgfp3",
		Name:        "广告图标",
		AllowedEdit: models.True,
	}

	handlers.InitLabel(sliderImageLabel, advertisementImageLabel)
}

func registerRoutes(engine *gin.Engine) {
	engine.Use(func(ctx *gin.Context) {
		cros.AddDefaultCrossSiteAccess(ctx.Writer.Header())
		ctx.Next()
	})
	engine.NoRoute(func(ctx *gin.Context) {
		if strings.ToUpper(ctx.Request.Method) == http.MethodOptions {
			ctx.Writer.WriteHeader(200)
		} else {
			http.NotFound(ctx.Writer, ctx.Request)
		}
	})
	engine.POST("/admin/sign-in", handlers.Login)
	engine.POST("/admin/sign-out", handlers.Logout)
	engine.GET("/admin/info", handlers.GetInfo)

	engine.GET("/advertisements", handlers.GetAdvertisements)
	engine.PUT("/advertisements", handlers.Auth, handlers.UpdateAdvertisements)

	engine.GET("/game/:id", handlers.GetGame)
	engine.GET("/result", handlers.GetGameResult)
	engine.GET("/subjects", handlers.GetSubjects)

	// 测试代理图片服务
	engine.GET("/proxy-images/:file", handlers.PsyTestImageService)
	// 图片资源静态服务
	// engine.GET(services.ImgService.RoutePattern(), handlers.LocalImageService)
	// 获得图片URL地址
	engine.GET("/image-url", handlers.GetImageUrl)
	// 管理网站图片的时候需要用到图片名称, 而图片名称是不能直接查看图片的, 因此需要用到代理
	engine.GET("/local-image-proxy", handlers.LocalImageProxy)
	// 某些网站的图片不允许跨域, 因此需要使用代理才能打开
	engine.GET("/image-proxy", handlers.ImageProxy)
	// 获得所有图片标签
	engine.GET("/admin/image-labels", handlers.ImageLabels)
	// 创建图片标签
	engine.POST("/admin/image-label", handlers.Auth, handlers.CreateImageLabel)
	// 修改图片标签
	engine.PUT("/admin/image-label", handlers.Auth, handlers.UpdateImageLabel)
	// 删除图片标签, 该标签下不存在任何图片
	engine.DELETE("/admin/image-label", handlers.Auth, handlers.DeleteImageLabel)
	// 统计标签图片数量
	engine.GET("/admin/count-images", handlers.CountLabelImages)
	// 获得标签下的图片列表
	engine.GET("/admin/label-images", handlers.GetLabelImages)
	// 上传图片
	engine.POST("/admin/images", handlers.UploadImages)
	// 删除图片
	engine.DELETE("/admin/label-images", handlers.Auth, handlers.DeleteLabelImages)

	engine.Static("/images", "./images")

	engine.GET("/sliders", handlers.GetSliders)
	engine.PUT("/sliders", handlers.Auth, handlers.UpdateSliders)
}

var letters = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")

// 创建指定位数的随机字符数组
func RandStr(bit int) []byte {
	return NewSrcRandByte(letters, bit)
}

// 从src中随机创建bit位的随机字符数组
func NewSrcRandByte(src []byte, bit int) []byte {
	bts := make([]byte, bit)
	r := make([]byte, bit)
	ln := len(src)
	rand.Read(bts)
	for idx, b := range bts {
		r[idx] = src[int(b)%ln]
	}
	return r
}
